package br.ufpe.cin.rdfilter.relevance;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.RDFNode;

import br.ufpe.cin.rdfilter.feedback.Annotation;
import br.ufpe.cin.rdfilter.feedback.Feedback;
import br.ufpe.cin.rdfilter.model.Manager;
import br.ufpe.cin.rdfilter.model.Source;
import br.ufpe.cin.rdfilter.query.QueryManager;
import br.ufpe.cin.rdfilter.util.FeedbackInference;
import br.ufpe.cin.rdfilter.util.FeedbackManager;
import br.ufpe.cin.rdfilter.util.LoadFeedback;
import br.ufpe.cin.rdfilter.util.Measure;

/**
 * 
 * @author helio Get a relevance value in this class
 * 
 */
public class Relevance {

	Double relevance = 0.0;
	Double sum = 0.0;
	List<Double> benefit = new ArrayList<Double>();
	Configuration config;
	List<Feedback> feedback = new ArrayList<Feedback>();
	List<Feedback> f_inferred = new ArrayList<Feedback>();
	List<br.ufpe.cin.rdfilter.model.Feedback> f_temp = new ArrayList<br.ufpe.cin.rdfilter.model.Feedback>();
	List<Annotation> annotation;
	List<Feedback> feedbackList;
	Manager m;
	Measure m_temp;
	Double b;
	private double[][] matrix = null;
	private List<Double> finalResult;
	
	public Relevance() {
		m = new Manager();
		List<br.ufpe.cin.rdfilter.model.Query> q = m.getQueries();
		List<Source> s = m.getSources();
		List<br.ufpe.cin.rdfilter.model.Feedback> fList;
		ResultSet results;
		boolean datasetError = false;
		List<String> listTerm = new ArrayList<String>();
		String temp = null;
		FeedbackInference fi = null;
		ArrayList<Double> weight = new ArrayList<Double>();
		FeedbackManager fm;
		QuerySolution result;
		Iterator<String> varNames;
		RDFNode answerField;
		
		startMatrix(s.size(), q.size());

		for (int i = 0; i < q.size(); i++) {
			weight.add(1.0);
		}

		for (int i = 0; i < s.size(); i++) {
			
				for (int j = 0; j < q.size(); j++) {
					if(i!=3 || i!=4 || i!=14 ){		
					fList = m.getFeedback(q.get(j));
					try {
//						System.out.println("Comecou a consulta... VAAAAAAAAAAI!!!!");
						QueryExecution queryExecution = QueryExecutionFactory
								.sparqlService(s.get(i).getUrl(), q.get(j)
										.getStatement());
//						System.out.println("Terminou a consulta, até que enfim....");
						results = queryExecution.execSelect();
						datasetError = false;
					} catch (Exception e) {
						results = null;
						datasetError = true;
					}

					if (datasetError) {
						System.out.println("  Endpoint " + s.get(i).getUrl()
								+ " fora do ar");
					} else {
						while (results.hasNext()) {
							result = results.next();
							varNames = result.varNames();
							
							temp = "";
//							while (varNames.hasNext()) {
								answerField = result.get(varNames.next());
							
//								temp = temp + answerField + ";";
//								System.out.println(answerField.toString());
//							}
//							listTerm.add(temp.substring(0, temp.length() - 1));
								listTerm.add(answerField.toString());
						}

						fm = new FeedbackManager(listTerm, fList);

						matrix[i][j] = fm.calculateBenefit();
					}
				}
			}
				
		}
		
		finalResult = getRelevance(weight);
		// System.out.println(endpoint);
		
		for (int i = 0; i < s.size(); i++) {		
				System.out.println("Valor de relevancia " +s.get(i).getLabel()+": "+finalResult.get(i));
			
		}
	
		
//		this.print();
	}

	public Relevance(String endpoint, String query, String label, String dir) {

		List<String> listTerm = new ArrayList<String>();
		String temp = null;
		ResultSet results;
		boolean datasetError = false;
		try {
			QueryExecution queryExecution = QueryExecutionFactory
					.sparqlService(endpoint, query);
			results = queryExecution.execSelect();
			datasetError = false;
		} catch (Exception e) {
			results = null;
			datasetError = true;
		}

		if (datasetError) {
			System.out.println("  Endpoint " + endpoint + "fora do ar");
		} else {

			// capturar linhas
			while (results.hasNext()) {

				QuerySolution result = results.next();

				Iterator<String> varNames = result.varNames();

				RDFNode answerField;
				temp = "";
//				while (varNames.hasNext()) {
					answerField = result.get(varNames.next());

//					temp = temp + answerField + ";";
					
//				}
//				listTerm.add(temp.substring(0, temp.length() - 1));
				listTerm.add(answerField.toString());
			}

//			QueryManager qm = new QueryManager();
//			qm.setDir(new File("list.txt"));
//			List<String> queries = qm.loadQuery();
//
//			LoadFeedback lf = new LoadFeedback();
//			feedback = lf.loadAll(queries);
//
//			for (int i = 0; i < queries.size(); i++) {

				Feedback f = null;
				annotation = new ArrayList<Annotation>();
				feedbackList = new ArrayList<Feedback>();
				try {

					FileReader reader = new FileReader(dir);
					BufferedReader in = new BufferedReader(reader);
					String line = null;
					String[] result = null;
					// List<Annotation> annotation = new
					// ArrayList<Annotation>();
					Annotation annot = null;
					List<String> tokens;
					List<String> terms;

					while ((line = in.readLine()) != null) {
						annot = new Annotation();
						terms = new ArrayList<String>();
						tokens = new ArrayList<String>();
						result = line.split(";");
						for (int j = 0; j < result.length; j++) {
							tokens.add(result[j]);
						}
						if (tokens.get(0).equals(label)) {
							annot.setIdQuery(tokens.get(0));
							annot.setIdUser(tokens.get(1));
							annot.setType(tokens.get(tokens.size() - 2));
							annot.setConfidence(tokens.get(tokens.size() - 1));
							for (int k = 2; k < tokens.size() - 2; k++) {
								terms.add(tokens.get(k));
							}
							annot.setTerms(terms);

							annotation.add(annot);
						}
					}
					in.close();
					reader.close();

					f = new Feedback(query, annotation);
					// feedbackList.add(f);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				feedbackList.add(f);
//			}

			ArrayList<Double> weight = new ArrayList<Double>();
			for (int i = 0; i < feedbackList.size(); i++) {
				weight.add(1.0);
			}

			FeedbackInference fi = null;

			for (int i = 0; i < feedbackList.size(); i++) {
				fi = new FeedbackInference(feedbackList.get(i).getAnnotation());
				fi.setVars(listTerm);
				f_inferred.add(fi.setInference2());
			}

			setRelevance(feedbackList, f_inferred, weight);
			System.out.println(endpoint+","+label);
			this.print();
		}
	}

	// relevance analysis
	public Relevance(List<Feedback> feedback, List<Feedback> inferred,
			List<Double> weight) {
		this.feedback = feedback;
		setRelevance(feedback, inferred, weight);
	}

	public Double getRelevance() {
		return relevance;
	}

	// old method to calculate relevance value
	public List<Double> getRelevance(List<Double> w) {

		List<Double> r_measure = new ArrayList<Double>();
		for (int i = 0; i < matrix.length; i++) { // quantidade de linhas
													// (source)
			relevance = 0.0;
			for (int j = 0; j < matrix[0].length; j++) { // quantidade de linhas
															// (queries)
				relevance += (matrix[i][j]) * (w.get(j));
				sum += w.get(j);
				// r_measure.add(e)
			}
			r_measure.add(relevance /= sum);
		}
		return r_measure;
	}

	/**
	 * 
	 * @param feedback
	 * @param inferred
	 * @param weight
	 * 
	 *            Get the initial feedback and feedback inferred and calculate R
	 */
	public void setRelevance(List<Feedback> feedback, List<Feedback> inferred,
			List<Double> weight) {
		for (int i = 0; i < feedback.size(); i++) {
			if ((inferred.get(i).getF_measure() / feedback.get(i)
					.getF_measure()) > 10.0)
				benefit.add(10.0);
			else
				benefit.add(inferred.get(i).getF_measure()
						/ feedback.get(i).getF_measure());
			// System.out.println(inferred.get(i).getF_measure()/feedback.get(i).getF_measure());
			relevance += (benefit.get(i)) * (weight.get(i));
			sum += weight.get(i);
		}
		relevance /= sum;
	}

	public List<Double> getBenefit() {
		return benefit;
	}

	public void setBenefit(List<Double> benefit) {
		this.benefit = benefit;
	}

	public Configuration getConfig() {
		return config;
	}

	public void setConfig(Configuration config) {
		this.config = config;
	}

	public void setRelevance(Double relevance) {
		this.relevance = relevance;
	}

	public void startMatrix(int i, int j) {
		matrix = new double[i][j];
		for (int k = 0; k < i; k++)
			for (int l = 0; l < j; l++)
				matrix[k][l] = 0.0;
	}

	public void print() {
		// System.out.println("Feedback before:");
		// System.out.println("TP: " + feedback.get(0).getTp());
		// System.out.println("FP: " + feedback.get(0).getFp());
		// System.out.println("FN: " + feedback.get(0).getFn());
		// System.out.println("Precision: " + feedback.get(0).getPrecision());
		// System.out.println("Recall: " + feedback.get(0).getRecall());
		// System.out.println("F-Measure: " + feedback.get(0).getF_measure());
		// System.out.println("Feedback after: ");
		// System.out.println("TP: " + f_infered.get(0).getTp());
		// System.out.println("FP: " + f_infered.get(0).getFp());
		// System.out.println("FN: " + f_infered.get(0).getFn());
		// System.out.println("Precision: " + f_infered.get(0).getPrecision());
		// System.out.println("Recall: " + f_infered.get(0).getRecall());
		// System.out.println("F-Measure: " + f_infered.get(0).getF_measure());
		//
		// System.out.println("Benefit: " + this.getBenefit());
		System.out.println("Benefit: " + this.getRelevance());
//		for (int i=0;i<finalResult.size();i++){
//			System.out.println("Valor de relevancia " +i+": "+finalResult.get(i));
//		}

	}
}